#include "board_dac.h"
#include "board_timer.h"
#include "ring_buffer.h"
#include "numerical.h"

/* dual dac mode */
#define DAC_BUF_LEN 128
#define DAC_DATA_ALIGN	DAC_ALIGN_12B_R

DAC_HandleTypeDef dacHandler;
DAC_ChannelConfTypeDef dacChannelConf;

/* TODO: dac need a ring buffer of uint32! */
ring_buffer dac_ch12_rb;

uint32_t dac_ch12_buf[DAC_BUF_LEN];
uint32_t dac_ch12_dma[DAC_BUF_LEN];

/* @brief	write dual values to ring buffer and convert later
 * @param	dev_num: currently not use
 */
uint16_t board_dac_dual_setval(uint32_t* reg_val, uint16_t* p_ch1, uint16_t*
                               p_ch2, uint16_t size)
{
    uint16_t i = 0;
    uint16_t ch1_val, ch2_val;
    for (i = 0; i < size; i++) {
        ch1_val = constraini(p_ch1[i], 0, 0x0fff);
        ch2_val = constraini(p_ch2[i], 0, 0x0fff);
        reg_val[i] = ((uint32_t)ch2_val << 16) | ch1_val;
    }
    return 0;
}

static inline uint32_t board_dac_compose(uint16_t ch1, uint16_t ch2)
{
    uint32_t reg_val = 0;
    ch1 = constraini(ch1, 0, 0x0fff);
    ch2 = constraini(ch2, 0, 0x0fff);
    reg_val = ((uint32_t)ch2 << 16) | ch1;
	return reg_val;
}


void board_dac_init(void)
{
#if DAC_USED
	rb_init(&dac_ch12_rb, DAC_BUF_LEN, dac_ch12_buf, ELEMENT_TYPE_U32);
	dacHandler.Instance = DAC;
    HAL_DAC_Init(&dacHandler);
    dacChannelConf.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
    dacChannelConf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
    HAL_DAC_ConfigChannel(&dacHandler, &dacChannelConf, DAC_CHANNEL_1);
    HAL_DAC_ConfigChannel(&dacHandler, &dacChannelConf, DAC_CHANNEL_2);
    dac_trigger_timer_init(10000);
//	board_dac_dual_setval(dac_ch12_buf, dac_test_data1, dac_test_data2,
//			      10);
//    HAL_DAC_Start_Dual_DMA(&dacHandler, (uint32_t*)dac_ch12_buf,
//                      10, DAC_ALIGN_12B_R);
//	HAL_DAC_Start_DMA(&dacHandler, DAC_CHANNEL_1, (uint32_t*)dac_test_data1,
//			10, DAC_ALIGN_12B_R);
#endif
}

void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{
#if DAC_USED
    GPIO_InitTypeDef	GPIO_InitStruct;
    static DMA_HandleTypeDef hdma_dac1;

    __HAL_RCC_DAC_CLK_ENABLE();
    DAC_CHANNEL1_GPIO_CLK_ENABLE();
    DAC_CHANNEL2_GPIO_CLK_ENABLE();
    DAC_DMA_CLK_ENABLE();

    GPIO_InitStruct.Pin = DAC_CHANNEL1_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(DAC_CHANNEL1_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = DAC_CHANNEL2_PIN;
    HAL_GPIO_Init(DAC_CHANNEL2_GPIO_PORT, &GPIO_InitStruct);

    hdma_dac1.Instance = DAC_DMA_STREAM1;
    hdma_dac1.Init.Channel = DAC_DMA_CHANNEL1;
    hdma_dac1.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_dac1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_dac1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_dac1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_dac1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_dac1.Init.Mode = DMA_NORMAL;
    hdma_dac1.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_dac1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_dac1);

    __HAL_LINKDMA(hdac,DMA_Handle1,hdma_dac1);

    HAL_NVIC_SetPriority(DAC_DMA_IRQn1, 0, 0);
    HAL_NVIC_EnableIRQ(DAC_DMA_IRQn1);
#endif
}

void HAL_DAC_MspDeInit(DAC_HandleTypeDef* hdac)
{
#if DAC_USED
	DAC_FORCE_RESET();
	DAC_RELEASE_RESET();
    HAL_GPIO_DeInit(DAC_CHANNEL1_GPIO_PORT, DAC_CHANNEL1_PIN);
    HAL_GPIO_DeInit(DAC_CHANNEL2_GPIO_PORT, DAC_CHANNEL2_PIN);
    HAL_DMA_DeInit(hdac->DMA_Handle1);
#endif
}

uint16_t board_write_dac(uint16_t *ch1_val, uint16_t *ch2_val,
                     uint16_t len)
{
	uint16_t cnt = 0;
	uint32_t reg_val = 0;
#if DAC_USED	
	for (cnt = 0; cnt < len; cnt++) {
		reg_val = board_dac_compose(ch1_val[cnt], ch2_val[cnt]);
		if (!rb_insert(&dac_ch12_rb, (void *)(&reg_val)))
			break;
	}
	uint32_t tmp = dacHandler.State;
	if (tmp == HAL_DAC_STATE_READY) {
		HAL_DAC_ConvCpltCallbackCh1(&dacHandler);
	}
#endif
	return cnt;
}

void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef* hdac)
{
#if DAC_USED
    if (hdac == &dacHandler) {
		uint16_t num = 0;
		while (!rb_is_empty(&dac_ch12_rb)) {
			rb_remove(&dac_ch12_rb, (void *)(&dac_ch12_dma[num++]));
			if (num == DAC_BUF_LEN) {
				break;
			}
		}
		if (num == 0) {
//			HAL_DAC_Stop_Dual_DMA(hdac);
			DAC_DISABLE_DMA(hdac, DAC_CHANNEL_1);
		} else {
			HAL_DAC_Start_Dual_DMA(hdac, dac_ch12_dma, num, DAC_ALIGN_12B_R);
		}
    }
#endif
}

void HAL_DAC_ConvCpltCallbackCh2(DAC_HandleTypeDef* hdac)
{
}

void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac)
{
}
